<script setup>
import Toast from '@vant/weapp/dist/toast/toast';
import myCanvas, { checkImageTransparency } from '@/utils/myCanvas'
import { getCategoryDetail } from "@/api/home";
import { imgUploadVerify } from '@/utils/auth'
import { ref, nextTick } from 'vue'
import { onLoad, onReady } from '@dcloudio/uni-app'



// 尺寸列表
const sizeList = ref([
    { id: 1, title: '原图', size: '', icon: 'ai-icon-yuantu' },
    { id: 2, title: '抖音', size: '1080*1920', icon: 'ai-icon-douyin' },
    { id: 3, title: '小红书', size: '1242*1660', icon: 'ai-icon-xiaohongshu' },
    { id: 4, title: '电商通用', size: '800*800', icon: 'ai-icon-taobao' },
    { id: 5, title: '咸鱼', size: '800*800', icon: 'ai-icon-xianyu' },
    { id: 6, title: '美团', size: '800*600', icon: 'ai-icon-meituan' },
    { id: 7, title: '公众号主图', size: '900*383', icon: 'ai-icon-gongzhonghao' },
    { id: 8, title: 'Amazon', size: '2000*2000', icon: 'ai-icon-yamaxun' },
])

// 页面携带参数
const queryItem = ref({})
// 查询详情信息
const queryInfo = ref({})
// 页面参数
const queryParams = ref({
    size: '',
    scale: 1,
})
// 提交数据
const queryData = ref({})

// size选中
const sizeCurrent = ref(0)


// footer滑动相关
const footerStartY = ref(0)
const footerHeight = ref(500) // 初始高度为 638rpx


let bgCanvas, imgCanvas = null

// 父盒子宽高
const fatherRect = ref({})
// 图片原始宽高
const oldImgRect = ref({})
// 图片宽高
const imgRect = ref({})
// 矩形盒子宽高
const rectAndImgCanvas = ref({})


// 输入尺寸宽高
const inputRect = ref({
    width: '',
    height: ''
})


// 定义变量用于记录单指触摸的起始位置
let startX = 0; // 单指触摸起始的 X 坐标
let startY = 0; // 单指触摸起始的 Y 坐标

// 定义变量用于记录双指触摸的初始间距和缩放比例
let initialDistance = 0; // 双指触摸的初始间距
let initialScale = queryParams.value.scale; // 初始缩放比例，默认为当前缩放比例

// 是否正在双指绘图
const twoMove = ref(false)


// 点击导出图片
async function exportImageFn() {
    if (!queryParams.value.imageFileUrl) {
        return Toast.fail('请先选择图片')
    }
    await exportCanvasImage()
    const data = Object.assign({}, queryItem.value, queryData.value)
    uni.navigateTo({
        url: `/draw/generationBgc/index?item=${JSON.stringify(data)}`,
    });
}


// 导出canvas图片
function exportCanvasImage() {
    return new Promise(resolve => {
        uni.canvasToTempFilePath({
            canvas: imgCanvas.canvas,
            x: rectAndImgCanvas.value.dx + 4,
            y: rectAndImgCanvas.value.dy + 4,
            width: rectAndImgCanvas.value.width - 4,
            height: rectAndImgCanvas.value.height - 8,
            destWidth: inputRect.value.width,
            destHeight: inputRect.value.height,
            success(res) {
                queryData.value.imageFileUrl = res.tempFilePath
                resolve()
            },
        })
    })
}




// 获取双指间距
function getDistance(touches) {
    const dx = touches[1].clientX - touches[0].clientX;
    const dy = touches[1].clientY - touches[0].clientY;
    return Math.sqrt(dx * dx + dy * dy);
}


// 边界判定方法
function calculateBoundary(newDx, newDy, imgWidth, imgHeight) {
    const minDx = rectAndImgCanvas.value.dx;
    const maxDx = rectAndImgCanvas.value.dx + rectAndImgCanvas.value.width - imgWidth;
    const minDy = rectAndImgCanvas.value.dy;
    const maxDy = rectAndImgCanvas.value.dy + rectAndImgCanvas.value.height - imgHeight;

    return {
        dx: Math.min(Math.max(newDx, minDx), maxDx),
        dy: Math.min(Math.max(newDy, minDy), maxDy),
    };
}




// 手指按下事件
function touchstart(event) {
    if (event.touches.length === 1) {
        twoMove.value = false
        const touch = event.touches[0];
        startX = touch.clientX - imgRect.value.dx;
        startY = touch.clientY - imgRect.value.dy;
    } else if (event.touches.length === 2) {
        twoMove.value = true
        initialDistance = getDistance(event.touches);
        initialScale = queryParams.value.scale;
    }
}

// 手指移动事件
function touchmove(event) {
    imgCanvas.ctx.save()
    if (event.touches.length === 1) {
        if (twoMove.value) return

        const touch = event.touches[0];
        let newDx = touch.clientX - startX;
        let newDy = touch.clientY - startY;

        const imgWidth = imgRect.value.width * queryParams.value.scale;
        const imgHeight = imgRect.value.height * queryParams.value.scale;

        const boundary = calculateBoundary(newDx, newDy, imgWidth, imgHeight);
        // imgRect.value.dx = boundary.dx;
        // imgRect.value.dy = boundary.dy;
        imgRect.value.dx = newDx;
        imgRect.value.dy = newDy;
    } else if (event.touches.length === 2) {
        const currentDistance = getDistance(event.touches);
        const scaleChange = currentDistance / initialDistance;
        const newScale = Math.min(2, Math.max(0.5, initialScale * scaleChange));

        const imgWidth = imgRect.value.width * newScale;
        const imgHeight = imgRect.value.height * newScale;

        const newDx = imgRect.value.dx + (imgRect.value.width * (queryParams.value.scale - newScale)) / 2;
        const newDy = imgRect.value.dy + (imgRect.value.height * (queryParams.value.scale - newScale)) / 2;

        const boundary = calculateBoundary(newDx, newDy, imgWidth, imgHeight);
        // imgRect.value.dx = boundary.dx;
        // imgRect.value.dy = boundary.dy;
        imgRect.value.dx = newDx;
        imgRect.value.dy = newDy;

        queryParams.value.scale = newScale;
    }

    const imgWidth = imgRect.value.width * queryParams.value.scale;
    const imgHeight = imgRect.value.height * queryParams.value.scale;

    imgCanvas.drawImage(
        queryParams.value.imageFileUrl,
        imgRect.value.dx,
        imgRect.value.dy,
        imgWidth,
        imgHeight,
        () => {
            imgCanvas.clearRect(0, 0,
                fatherRect.value.width,
                fatherRect.value.height);
            imgCanvas.ctx.clip()
        },
        () => {
            imgCanvas.ctx.restore()
        }
    );
}



// 高度输入
function heightChange() {
    if (inputRect.value.width && inputRect.value.height) {
        const radioInfo = getAspectRatioFn({
            width: oldImgRect.value.width,
            height: oldImgRect.value.height,
            ratio: `${inputRect.value.width}*${inputRect.value.height}`
        });
        imgRect.value.width = radioInfo.width;
        imgRect.value.height = radioInfo.height;
    } else {
        imgRect.value.width = oldImgRect.value.width;
        imgRect.value.height = oldImgRect.value.height;
    }
    imgRect.value.dy = (rectAndImgCanvas.value.height - imgRect.value.height) / 2 + rectAndImgCanvas.value.dy;
    sizeCurrent.value = -1
    // 重置双指触摸的初始间距和缩放比例
    initialDistance = 0;
    initialScale = 0;
    queryParams.value.scale = 1;
    loadDrawImage({ id: 'custom' });

}

// 宽度输入
function widthChange() {
    if (inputRect.value.width && inputRect.value.height) {
        const radioInfo = getAspectRatioFn({
            width: oldImgRect.value.width,
            height: oldImgRect.value.height,
            ratio: `${inputRect.value.width}*${inputRect.value.height}`
        });
        imgRect.value.width = radioInfo.width;
        imgRect.value.height = radioInfo.height;
    } else {
        imgRect.value.width = oldImgRect.value.width;
        imgRect.value.height = oldImgRect.value.height;
    }
    imgRect.value.dx = (rectAndImgCanvas.value.width - imgRect.value.width) / 2 + rectAndImgCanvas.value.dx;
    sizeCurrent.value = -1
    // 重置双指触摸的初始间距和缩放比例
    initialDistance = 0;
    initialScale = 0;
    queryParams.value.scale = 1;
    loadDrawImage({ id: 'custom' });
}

function loadDrawImage(e) {
    if (e.id === 1) {
        rectAndImgCanvas.value.width = oldImgRect.value.width;
        rectAndImgCanvas.value.height = oldImgRect.value.height;
    } else if (e.id === 'custom') {
        // 用户输入的自定义尺寸
        const customWidth = parseInt(inputRect.value.width, 10);
        const customHeight = parseInt(inputRect.value.height, 10);

        if (customWidth && customHeight) {
            const radioInfo = getAspectRatioFn({
                width: oldImgRect.value.width,
                height: oldImgRect.value.height,
                ratio: `${customWidth}*${customHeight}`,
            });

            const widthRatio = fatherRect.value.width / radioInfo.width;
            const heightRatio = fatherRect.value.height / radioInfo.height;
            const scaleRatio = Math.min(widthRatio, heightRatio);

            rectAndImgCanvas.value.width = radioInfo.width * scaleRatio;
            rectAndImgCanvas.value.height = radioInfo.height * scaleRatio;
        } else {
            rectAndImgCanvas.value.width = oldImgRect.value.width;
            rectAndImgCanvas.value.height = oldImgRect.value.height;
        }
    } else {
        const radioInfo = getAspectRatioFn({
            width: oldImgRect.value.width,
            height: oldImgRect.value.height,
            ratio: e.size,
        });

        const widthRatio = fatherRect.value.width / radioInfo.width;
        const heightRatio = fatherRect.value.height / radioInfo.height;
        const scaleRatio = Math.min(widthRatio, heightRatio);

        rectAndImgCanvas.value.width = radioInfo.width * scaleRatio;
        rectAndImgCanvas.value.height = radioInfo.height * scaleRatio;
    }

    const canvasWidth = fatherRect.value.width;
    const canvasHeight = fatherRect.value.height;

    nextTick(() => {
        rectAndImgCanvas.value.dx = (canvasWidth - rectAndImgCanvas.value.width) / 2;
        rectAndImgCanvas.value.dy = (canvasHeight - rectAndImgCanvas.value.height) / 2;

        bgCanvas.drawBorderedRect(
            rectAndImgCanvas.value.dx,
            rectAndImgCanvas.value.dy,
            rectAndImgCanvas.value.width,
            rectAndImgCanvas.value.height,
            {
                borderColor: '#FFF',
                backgroundImage: 'https://devweb.topyunliu.com/upload/2025/03/30/file_20250330134701A002.png',
                drawImgBefore: () => {
                    bgCanvas.clearRect(0, 0, fatherRect.value.width, fatherRect.value.height);
                    bgCanvas.ctx.beginPath();
                    bgCanvas.ctx.rect(rectAndImgCanvas.value.dx, rectAndImgCanvas.value.dy, rectAndImgCanvas.value.width, rectAndImgCanvas.value.height);
                    bgCanvas.ctx.lineWidth = 2;
                    bgCanvas.ctx.strokeStyle = '#FFF';
                    bgCanvas.ctx.stroke();
                    bgCanvas.ctx.closePath();
                }
            }
        );

        imgCanvas.drawBorderedRect(
            rectAndImgCanvas.value.dx,
            rectAndImgCanvas.value.dy,
            rectAndImgCanvas.value.width,
            rectAndImgCanvas.value.height,
            {
                borderColor: 'transparent',
                backgroundColor: 'transparent',
            }
        );

        const imgAspectRatio = oldImgRect.value.width / oldImgRect.value.height;
        const canvasAspectRatio = rectAndImgCanvas.value.width / rectAndImgCanvas.value.height;

        if (imgAspectRatio > canvasAspectRatio) {
            imgRect.value.width = rectAndImgCanvas.value.width;
            imgRect.value.height =
                (rectAndImgCanvas.value.width / oldImgRect.value.width) * oldImgRect.value.height;
        } else {
            imgRect.value.height = rectAndImgCanvas.value.height;
            imgRect.value.width =
                (rectAndImgCanvas.value.height / oldImgRect.value.height) * oldImgRect.value.width;
        }

        imgRect.value.dx = (rectAndImgCanvas.value.width - imgRect.value.width) / 2 + rectAndImgCanvas.value.dx;
        imgRect.value.dy = (rectAndImgCanvas.value.height - imgRect.value.height) / 2 + rectAndImgCanvas.value.dy;
        imgCanvas.drawImage(
            queryParams.value.imageFileUrl,
            imgRect.value.dx,
            imgRect.value.dy,
            imgRect.value.width,
            imgRect.value.height,
            () => {
                imgCanvas.clearRect(0, 0, fatherRect.value.width, fatherRect.value.height);
                // 保存画布状态（裁剪前）
                imgCanvas.ctx.save();
                imgCanvas.ctx.clip();
            },
            () => {
                // 恢复画布状态（移除裁剪区域）
                imgCanvas.ctx.restore();
                Toast.clear();
            }
        );
    });
}

// 根据选中的宽高比计算图片的宽高
// 传入图片宽高和选中宽高比，返回新的宽高
function getAspectRatioFn({ width, height, ratio }) {
    const [ratioWidth, ratioHeight] = ratio.split('*').map(Number); // 解构宽高比
    const aspectRatio = (ratioWidth / ratioHeight).toFixed(2); // 选中宽高比
    const imgAspectRatio = (width / height).toFixed(2); // 图片宽高比

    const imgRect = { width, height };

    if (imgAspectRatio > aspectRatio) {
        // 图片宽高比大于选择的比例
        imgRect.height = (width / ratioWidth) * ratioHeight;
    } else if (imgAspectRatio < aspectRatio) {
        // 图片宽高比小于选择的比例
        imgRect.width = (height / ratioHeight) * ratioWidth;
    }

    return imgRect;
}


// 计算图片宽高比及外部边框盒子的宽高
async function calculatePicAspectRatio(path) {
    const { width, height } = await uni.getImageInfo({ src: path })

    const widthRatio = fatherRect.value.width / width;
    const heightRatio = fatherRect.value.height / height;
    const scaleRatio = Math.min(widthRatio, heightRatio);

    // 计算缩放后的图片宽度和高度
    const scaledWidth = width * scaleRatio;
    const scaledHeight = height * scaleRatio;

    // 基准尺寸
    oldImgRect.value = {
        width: scaledWidth,
        height: scaledHeight
    }
    sizeList.value[0].size = `${width}*${height}`
    inputRect.value = {
        width: width,
        height: height
    }

    // 绘制尺寸
    imgRect.value = {
        width: scaledWidth,
        height: scaledHeight
    }
}



// 尺寸切换
function changeSize(e, i) {
    // 更新当前选中的尺寸索引
    sizeCurrent.value = i;
    // 更新查询参数中的尺寸
    queryParams.value.size = e.size;
    // 重置底部高度为初始值
    footerHeight.value = 500;
    // 重置双指触摸的初始间距和缩放比例
    initialDistance = 0;
    initialScale = 0;
    queryParams.value.scale = 1;

    // 更新输入框中的宽高值
    inputRect.value = {
        width: e.size.split('*')[0], // 提取宽度
        height: e.size.split('*')[1] // 提取高度
    };
    // 加载并绘制图片
    loadDrawImage(e);
}



// 相册选择
async function uploadImgFn() {
    const res = await imgUploadVerify({
        format: 'png',
    })
    try {
        await checkImageTransparency(res)
        queryParams.value.imageFileUrl = res
        calculatePicAspectRatio(queryParams.value.imageFileUrl).then(() => {
            // 重置双指触摸的初始间距和缩放比例
            initialDistance = 0;
            initialScale = 0;
            queryParams.value.scale = 1;
            loadDrawImage(sizeList.value[sizeCurrent.value])
        })
    } catch (error) {
        Toast.fail('请选择png格式的透明背景图')
    }
}




// 底部手指按下事件
function footerTouchStart(event) {
    footerStartY.value = event.touches[0].clientY
}

// 底部滑动事件
function footerTouchMove(event) {
    const endY = event.touches[0].clientY
    const deltaY = endY - footerStartY.value

    if (deltaY < -30) {
        // 向上滑动
        footerHeight.value = 795
    } else if (deltaY > 30) {
        // 向下滑动
        footerHeight.value = 500
    }
}


// 获取分类详情
async function getCategoryDetailFn() {
    const res = await getCategoryDetail(queryItem.value.id)
    queryInfo.value = res.data
}


onReady(() => {
    uni.createSelectorQuery().select('.container').boundingClientRect((res) => {
        fatherRect.value = {
            width: res.width,
            height: res.height
        }
        bgCanvas = new myCanvas('bgCanvas')
        imgCanvas = new myCanvas('imgCanvas')
    }).exec()
})

onLoad((e) => {
    if (e.item) {
        queryItem.value = JSON.parse(e.item)
    }
    getCategoryDetailFn()
})
</script>

<template>
    <div class='newGenerationBgImgSize'>
        <NavBar :zIndex="5">{{ queryInfo?.title }}</NavBar>
        <div class="container">
            <div v-if="!queryParams.imageFileUrl" class="uploadImgBtn" @click="uploadImgFn">
                <i class="iconfont ai-icon-xiangcexuanze"></i>
                相册选择
            </div>

            <canvas type="2d" id="bgCanvas" class="bgCanvas"></canvas>
            <canvas type="2d" id="imgCanvas" class="imgCanvas" @touchstart="touchstart"
                @touchmove.stop="touchmove"></canvas>

        </div>
        <div class="footer" @touchstart="footerTouchStart" @touchmove.stop="footerTouchMove">
            <div class="footer_placeholder"></div>
            <div class="footer_content" :style="{ height: footerHeight + 'rpx' }">
                <div class="title_box">
                    <div class="uploadImg" @click="uploadImgFn" v-if="queryParams.imageFileUrl">
                        <i class="iconfont ai-icon-shangchuan"></i>
                        <div>上传图片</div>
                    </div>
                    <div class="title">选择尺寸</div>
                    <div class="icon_box" @click="exportImageFn">
                        <i class="iconfont ai-icon-a-shibieleixingqueren"></i>
                    </div>
                </div>
                <div class="size_top">
                    <div class="size_ipt">
                        <div>宽</div>
                        <input v-model="inputRect.width" @change="widthChange" type="number" class="inputSty"
                            placeholder="宽度" maxlength="4" />
                        <div>px</div>
                    </div>
                    <div class="icon_box">
                        <i class="iconfont ai-icon-guanlian"></i>
                    </div>
                    <div class="size_ipt">
                        <div>高</div>
                        <input v-model="inputRect.height" @change="heightChange" type="number" class="inputSty"
                            placeholder="高度" maxlength="4" />
                        <div>px</div>
                    </div>
                </div>
                <div class="size_content">
                    <div class="size_item" v-for="item, index of sizeList" @click="changeSize(item, index)" :key="item?.id"
                        :class="{ active: sizeCurrent === index }">
                        <div class="icon_box">
                            <i :class="`iconfont ${item?.icon}`"></i>
                        </div>
                        <div class="size_text">
                            <div class="label">{{ item?.title }}</div>
                            <div class="size" v-if="item.id !== 1">{{ item?.size }}</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <van-toast id="van-toast" />
</template>

<style lang='scss' scoped>
.newGenerationBgImgSize {
    height: 100vh;
    display: flex;
    flex-direction: column;

    .container {
        flex: 1;
        position: relative;

        .bgCanvas,
        .imgCanvas {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;

            &.bgCanvas {
                z-index: 1;
            }

            &.imgCanvas {
                z-index: 2;
            }
        }

        .uploadImgBtn {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            z-index: 10;
            width: 228rpx;
            height: 84rpx;
            border-radius: 45rpx;
            background-color: transparent;
            border: 3rpx solid var(--a-main-color);
            color: var(--a-one-text-color);
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 10rpx;
        }
    }

    .footer {

        .footer_placeholder {
            height: 500rpx;
        }

        .footer_content {
            box-sizing: border-box;
            position: fixed;
            bottom: 0;
            left: 0;
            z-index: 5;
            width: 100%;
            padding: 24rpx 30rpx;
            background-color: var(--a-main-tabNav-bg-color);
            transition: height 0.3s ease-in-out;

            .title_box {
                display: flex;
                align-items: center;
                justify-content: center;

                .uploadImg {
                    position: absolute;
                    top: 24rpx;
                    left: 30rpx;
                    font-size: 20rpx;
                    text-align: center;
                    color: var(--a-two-text-color);
                }

                .title {
                    font-size: 32rpx;
                    color: var(--a-one-text-color);
                    font-weight: bold;
                    text-align: center;
                }

                .icon_box {
                    position: absolute;
                    top: 24rpx;
                    right: 30rpx;
                    width: 64rpx;
                    height: 64rpx;
                    border-radius: 50%;
                    display: flex;
                    align-items: center;
                    justify-content: center;

                    .iconfont {
                        font-size: 36rpx;
                        color: var(--a-two-text-color);
                    }
                }
            }

            .size_top {
                display: flex;
                align-items: center;
                justify-content: space-between;
                gap: 17rpx;
                margin-top: 22rpx;

                .size_ipt {
                    box-sizing: border-box;
                    flex: 1;
                    height: 76rpx;
                    background: var(--a-main-box-bg-color);
                    border-radius: 12rpx;
                    display: flex;
                    align-items: center;
                    justify-content: space-between;
                    padding: 0 53rpx;
                    color: var(--a-three-text-color);

                    .inputSty {
                        flex: 1;
                        text-align: center;
                        color: var(--a-one-text-color);
                    }
                }

                .icon_box {
                    width: 64rpx;
                    height: 64rpx;
                    background: var(--a-main-box-bg-color);
                    border-radius: 50%;
                    display: flex;
                    align-items: center;
                    justify-content: center;

                    .iconfont {
                        color: var(--a-one-text-color);
                    }
                }
            }

            .size_content {
                display: grid;
                grid-template-columns: repeat(4, 1fr);
                grid-column-gap: 14rpx;
                grid-row-gap: 30rpx;
                margin-top: 30rpx;

                .size_item {
                    &.active {
                        .icon_box {
                            border: 4rpx solid #83CD88;
                        }

                        .size_text {
                            color: var(--a-main-color);

                            .size {
                                color: var(--a-main-color);
                            }
                        }
                    }

                    .icon_box {
                        box-sizing: border-box;
                        width: 162rpx;
                        height: 162rpx;
                        background: var(--a-main-box-bg-color);
                        border-radius: 20rpx;
                        display: flex;
                        align-items: center;
                        justify-content: center;

                        .iconfont {
                            font-size: 82rpx;
                            color: var(--a-one-text-color);
                        }
                    }

                    .size_text {
                        font-size: 22rpx;
                        color: var(--a-one-text-color);
                        text-align: center;

                        .label {
                            margin-top: 20rpx;
                        }

                        .size {
                            color: var(--a-three-text-color);
                            margin-top: 8rpx;
                        }
                    }
                }
            }
        }

    }
}
</style>